Skip to content

fix(#398): audit Turnstile failure handling, add regression tests - #533

Open
Vyacheslav-Tomashevskiy wants to merge 1 commit into
Northgate-Systems:mainfrom
Vyacheslav-Tomashevskiy:fix/398-turnstile-tests
Open

fix(#398): audit Turnstile failure handling, add regression tests#533
Vyacheslav-Tomashevskiy wants to merge 1 commit into
Northgate-Systems:mainfrom
Vyacheslav-Tomashevskiy:fix/398-turnstile-tests

Conversation

@Vyacheslav-Tomashevskiy

Copy link
Copy Markdown
Contributor

Closes #398.

What I found

Audited src/lib/turnstile.ts and its two call sites (api/auth/login, api/auth/register). The failure handling was already correct:

  • Missing token, Cloudflare rejection, network error, and a malformed (non-JSON) response from Cloudflare all return a structured {success: false, reason} instead of throwing.
  • Both routes already turn a failed check into a 400 (errorResponse(`Verification failed: ${reason}`, 400)), not a generic 500.

The actual gap was that none of it had a single test - so nothing would catch it if this ever regressed.

What I did

  • src/lib/__tests__/turnstile.test.ts — unit tests for every branch: no secret configured (dev skip), missing/empty token, Cloudflare success, Cloudflare rejection with error-codes, rejection without error-codes (fallback reason), network failure, and a non-JSON response body.
  • src/app/api/auth/login/__tests__/route.test.ts — route-level regression test proving a failed Turnstile check surfaces as 400 with the exact user-facing message, not 500 - and that the route short-circuits before touching the database (no supabase mock needed in this file; if the route tried to query it after a failed check, the test would throw instead of silently passing).

9 new tests, all passing.

Verified live

npm run dev
POST /api/auth/login  {"email":"a@b.com","password":"x","turnstileToken":""}
-> 400 {"success":false,"error":"Please complete the verification challenge"}

🔴 Heads up for review, same as #529/#530/#531/#532: a clean main checkout currently has a pre-existing bug from #527 (missing isValidStellarPublicKey import in validations.ts, fix pending in #529) that breaks module-load for anything importing validations.ts - including the login route, since it uses loginSchema. I confirmed the 9 new tests genuinely pass by temporarily restoring the one missing import line locally, running the full suite (73/75 - the other 2 failures are the same already-reported validations.test.ts fixture issue, unrelated to this change), then reverting before committing. npm run build also verified clean with that same temporary local fix in place.

eslint / tsc --noEmit clean on every file this PR touches.

…ression tests

Audited src/lib/turnstile.ts and its two call sites (login, register):
- Missing token, Cloudflare rejection, network error, and a malformed
  (non-JSON) response from Cloudflare all already return a structured
  {success:false, reason} instead of throwing.
- Both auth/login and auth/register already turn that into a 400
  (errorResponse(`Verification failed: ${reason}`, 400)) instead of a
  generic 500.

So the behavior the issue asks to confirm was already correct - the
actual gap was that none of it had a single test, so nothing would
catch a regression if it broke. Added:

- src/lib/__tests__/turnstile.test.ts: unit tests for every branch -
  no secret configured (dev skip), missing/empty token, Cloudflare
  success, Cloudflare rejection with error-codes, rejection without
  error-codes (fallback reason), network failure, and a non-JSON
  response body.
- src/app/api/auth/login/__tests__/route.test.ts: route-level
  regression test proving a failed Turnstile check surfaces as 400
  with the exact user-facing message, not 500 - and that the route
  short-circuits before ever touching the database (no supabase mock
  needed in this file; if the route tried to query it after a failed
  check, the test would throw instead of silently passing).

9 new tests, all passing. Verified live via npm run dev: POST
/api/auth/login with an empty turnstileToken returns 400
{"success":false,"error":"Please complete the verification
challenge"}, not 500.

Like Northgate-Systems#529/Northgate-Systems#530/Northgate-Systems#531/Northgate-Systems#532 before it, this branch is cut from a main
that still has the pre-existing missing isValidStellarPublicKey
import bug (from Northgate-Systems#527, fix pending in Northgate-Systems#529), which breaks module-load
for anything importing validations.ts - including the login route,
since it uses loginSchema. Confirmed the 9 new tests genuinely pass by
temporarily restoring the one missing import line locally, running
the full suite (73/75, the other 2 failures are the same
already-reported validations.test.ts fixture issue, unrelated to this
change), then reverting before this commit. npm run build also
verified clean with that same temporary local fix in place.

eslint and tsc --noEmit clean on every file this PR touches.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 9, 2026

Copy link
Copy Markdown

Someone is attempting to deploy a commit to the codex723's projects Team on Vercel.

A member of the Team first needs to authorize it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Audit Turnstile (src/lib/turnstile.ts) failure handling

1 participant